import { APP_SECRET } from "./../constants/index";
import * as crypto from 'crypto';
import * as _ from "lodash";
import { ObjectId } from 'mongodb';
import { isValidObjectId } from 'mongoose';
import { BASE_QUERY } from "../schedule";
import { v4 } from 'uuid';
import { HError } from "../common/error";
import { HCode } from "../common/code";
import * as moment from "moment-timezone";
import { SERVER_TIMEZONE } from "../constants";

export const md5 = (content: string): string => {
  return crypto.createHash('md5').update(content).digest('hex');
}

export const sign = (params: object) => {
  let result = `${APP_SECRET}`;
  const keys = Object.keys(params).sort();
  keys.forEach(key => {
    result += `${key}${params[key]}`;
  });
  return md5(result).toUpperCase();
}


export const parseId = (id?: string | ObjectId): ObjectId => {
  if (id) {
    if(isValidObjectId(id)) {
      return new ObjectId(id);
    } else {
      throw new HError(HCode.invalidInput, `id is invalid: ${id}`)
    }
  } else {
    return new ObjectId();
  }
}

export const uuid = () => {
  return v4();
}

export const camelToUnderline = <T extends Object, U extends Object>(data: T): U => {
  const keys = Object.keys(data);
  const obj: U = Object.create({});
  keys.forEach(camelKey => {
    const underlineKey = camelKey.replace(/([A-Z])/g,"_$1").toLowerCase().replace(/^_/, "");
    if (_.isArray(data[camelKey]) && _.isPlainObject(data[camelKey][0])) {
      obj[underlineKey] = data[camelKey].map((dt: object) => { return camelToUnderline(dt); });
    } else if (_.isPlainObject(data[camelKey])) {
      obj[underlineKey] = camelToUnderline(data[camelKey]);
    } else {
      obj[underlineKey] = data[camelKey];
    }
  })
  return obj;
}

export const serverMoment = (time?: any) => {
  return moment(time).tz(SERVER_TIMEZONE);
}

export const buildQuery = (query: object = {}) => {
  const fixedQuery = Object.assign({}, BASE_QUERY, query)
  const finalQuery = Object.assign({}, fixedQuery, { sign: sign(fixedQuery) });
  return finalQuery;
}